﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Media;

namespace Minas {
    public partial class Janela :Form {
        //Guarda 1 para vez do P1, e 2 para vez do P2
        private int vez; 
        //Guarda scores
        private int score1;
        private int score2;

        //Sons
        private bool som;
        private SoundPlayer bomba = new SoundPlayer("Sound/bomb.wav");
        private SoundPlayer applause = new SoundPlayer("Sound/applause.wav");
        private SoundPlayer erro = new SoundPlayer("Sound/erro.wav");
        
        //
        // Método construtor.
        // Inicializa o componente e chama os metodos responsaveis
        // pela logica do jogo.
        //
        public Janela() {
            InitializeComponent();
            som = true;
            try {
                bomba.Load();
                applause.Load();
                erro.Load();

            } catch (Exception ex) {
                som = false;
            }
            novoJogo();            
        }

        
        

        public void novoJogo() {
            for (int i = 0; i < 19; i++) {
                for (int j = 0; j < 19; j++) {
                    this.sqm1[i, j].inicializar(0);
                }
            }
            colocaBordas();
            colocaMinas(51);
            colocaNumeros();
            
            //Define a vez de qual player
            Random x = new Random();
            this.vez = x.Next(1,2);
            mudaVez();
            this.score1 = 0;
            this.score2 = 0;
            this.LB_S1.Text = "0";
            this.LB_S2.Text = "0";
        }

        //
        // Menu :: Novo Jogo
        //
        private void Opcoes_novo_MouseUp(object sender, MouseEventArgs e) {
            novoJogo();
        }
        //
        // Menu :: About
        //
        private void Opcoes_about_MouseUp(object sender, MouseEventArgs e) {
            AboutBox About = new AboutBox();
            About.ShowDialog();
        }
        //
        // Método para o Evento de soltar o botão do mouse em cima de um SQM
        //
        private void sqm1_MouseUp(object sender, MouseEventArgs e) {
            if ((vez == 2) || (vez == 1)) {
                //Pega o sqm que chamou o evento
                Sqm x = (Sqm) sender;
                int i = 0;
                int j = 0;
                bool achou = false;
                while (!achou && i < 18) {
                    j = 0;
                    while (!achou && j < 18) {
                        if (this.sqm1[i, j].Equals(x)) {
                            achou = true;
                        }
                        j++;
                    }
                    i++;
                }
                i--;
                j--;

                // Revela o valor do SQM.
                int Resultado = 0;

                if (x.status == false) {
                    Resultado = x.abrir(vez);
                    // Se o resultado é zero, revela campos ao redor
                    if (Resultado == 0) {
                        abrirZeros(1, i - 1, j - 1);
                        abrirZeros(1, i - 1, j);
                        abrirZeros(1, i - 1, j + 1);
                        abrirZeros(1, i, j - 1);
                        abrirZeros(1, i, j + 1);
                        abrirZeros(1, i + 1, j - 1);
                        abrirZeros(1, i + 1, j);
                        abrirZeros(1, i + 1, j + 1);
                        mudaVez();
                    } else if (Resultado == -1) {
                        marcaPto(vez);
                    } else {
                        mudaVez();
                    }
                }
            } 
        }


        //
        // Método que coloca bordas (valor -2) na matriz do campo minado.
        //
        private void colocaBordas() {
            for (int i = 0; i < 19; i++) {
                this.sqm1[i, 0].inicializar(-2);
                this.sqm1[i, 17].inicializar(-2);
            }
            for (int i = 0; i < 19; i++) {
                this.sqm1[0, i].inicializar(-2);
                this.sqm1[17, i].inicializar(-2);
            }
        }


        //
        // Método que coloca as 51 minas no campo, utilizando números randomicos
        //
        private void colocaMinas(int minas) {
            Random R = new Random();
            int x, y;
            while (minas > 0) {
                x = R.Next(1, 16);
                y = R.Next(1, 16);
                if (this.sqm1[x, y].tipo != -1) {
                    this.sqm1[x, y].inicializar(-1);
                    minas--;
                }                
            }
        }

        //
        // Método que calcula o valor dos campos que não possuem minas.
        // Pré-requisito: colocaBordas() , colocaMinas()
        //
        private void colocaNumeros() {
            int x, y, cont;
            x = 1;
            y = 1;
            cont = 0;
            for (x = 1; x <= 16; x++) {
                for (y = 1; y <= 16; y++) {
                    if (this.sqm1[x, y].tipo != -1) {
                        if (this.sqm1[x - 1, y - 1].tipo == -1)
                            cont++;
                        if (this.sqm1[x - 1, y].tipo == -1)
                            cont++;
                        if (this.sqm1[x - 1, y + 1].tipo == -1)
                            cont++;
                        if (this.sqm1[x, y - 1].tipo == -1)
                            cont++;
                        if (this.sqm1[x, y + 1].tipo == -1)
                            cont++;
                        if (this.sqm1[x + 1, y - 1].tipo == -1)
                            cont++;
                        if (this.sqm1[x + 1, y].tipo == -1)
                            cont++;
                        if (this.sqm1[x + 1, y + 1].tipo == -1)
                            cont++;

                        this.sqm1[x, y].inicializar(cont);
                    }
                    cont = 0;
                }
            }
        }

        //
        //Método recursivo para abrir campos que não contem nenhuma
        //mina ao redor.
        //
        private int abrirZeros(int jogador, int i, int j) {
            int resultado = 0;
            resultado = this.sqm1[i, j].abrir(jogador);

            if (resultado == 0) {
                abrirZeros(jogador, i - 1, j - 1);
                abrirZeros(jogador, i - 1, j);
                abrirZeros(jogador, i - 1, j + 1);
                abrirZeros(jogador, i, j - 1);
                abrirZeros(jogador, i, j + 1);
                abrirZeros(jogador, i + 1, j - 1);
                abrirZeros(jogador, i + 1, j);
                abrirZeros(jogador, i + 1, j + 1);
            }

            return resultado;
        }


        //
        // Método para mudar a vez do jogador.
        //
        private void mudaVez() {
            if ((score1 < 26) && (score2 < 26)) {
                if (som) {erro.Play();}
                if (this.vez == 1) {
                    this.vez = 2;
                    this.LB_P2.BackColor = System.Drawing.Color.Black;
                    this.LB_P2.ForeColor = System.Drawing.Color.Yellow;
                    this.LB_P1.BackColor = System.Drawing.Color.LightGray;
                    this.LB_P1.ForeColor = System.Drawing.Color.Black;
                } else {
                    this.vez = 1;
                    this.LB_P1.BackColor = System.Drawing.Color.Black;
                    this.LB_P1.ForeColor = System.Drawing.Color.Yellow;
                    this.LB_P2.BackColor = System.Drawing.Color.LightGray;
                    this.LB_P2.ForeColor = System.Drawing.Color.Black;
                }
            } else {
                this.vez = 3;               
            }
        }

        //
        // Metodo para marcar pontuação
        //
        private void marcaPto(int jogador) {
            if (jogador == 1) {
                this.score1++;
                this.LB_S1.Text = this.score1.ToString();
            } else if (jogador == 2) {
                this.score2++;
                this.LB_S2.Text = this.score2.ToString();
            }

            if ((score1 == 26) || (score2 == 26)) {
                this.vez = 10;
                for (int i = 1; i <= 16; i++) {
                    for (int j = 1; j <= 16; j++) {
                        if (this.sqm1[i, j].tipo == -1) {
                            this.sqm1[i, j].Image = global::Minas.Properties.Resources.mina;
                        }
                    }
                }
                if (som) { applause.Play(); }
            } else {
                if (som) { bomba.Play(); }
            }            
        }
    }
}